{-Problem 1
Find the last element of a list.
Example in Haskell:
Prelude> myLast [1,2,3,4]
4
Prelude> myLast ['x','y','z']
'z'
-}
myLast :: [a] -> a
myLast li = li !! (length li -1)

myLast' = head . reverse

{-Problem 2
Find the last but one element of a list.
Example in Haskell:
Prelude> myButLast [1,2,3,4]
3
Prelude> myButLast ['a'..'z']
'y'
-}
myButLast :: [a] -> a
myButLast li = li !! (length li -2)

{-Problem 3
Find the K'th element of a list. The first element in the list is number 1.
Example:
Example in Haskell:
Prelude> elementAt [1,2,3] 2
2
Prelude> elementAt "haskell" 5
'e'
-}
elementAt :: [a] -> Int -> a
elementAt li idx = li !! (idx - 1)

{-Problem 4
Find the number of elements of a list.
Example in Haskell:
Prelude> myLength [123, 456, 789]
3
Prelude> myLength "Hello, world!"
13
-}
myLength :: [a] -> Int
myLength li = length li

{-Problem 5
Reverse a list.
Example in Haskell:
Prelude> myReverse "A man, a plan, a canal, panama!"
"!amanap ,lanac a ,nalp a ,nam A"
Prelude> myReverse [1,2,3,4]
[4,3,2,1]
-}
myReverse :: [a] -> [a]
myReverse = reverse

{-Problem 6
Find out whether a list is a palindrome. 
A palindrome can be read forward or backward; 
e.g. (x a m a x).
Example in Haskell:
*Main> isPalindrome [1,2,3]
False
*Main> isPalindrome "madamimadam"
True
*Main> isPalindrome [1,2,4,8,16,8,4,2,1]
True
-}
isPalindrome :: (Eq a) => [a] -> Bool
isPalindrome list
    | len == 0            = True
    | len == 1            = True
    | firstOne /= lastOne = False
    | firstOne == lastOne = isPalindrome newList
    where len = length list
          firstOne = head list
          lastOne  = last list
          newList  = drop 1 $ init list

{-Problem 8
Eliminate consecutive duplicates of list elements.
If a list contains repeated elements they should be 
replaced with a single copy of the element. 
The order of the elements should not be changed.
Example:
* (compress '(a a a a b c c a a d e e e e))
(A B C A D E)
Example in Haskell:
> compress "aaaabccaadeeee"
"abcade"
-}
compress :: (Eq a) => [a] -> [a]
compress []  = []
compress [x] = [x]
compress (x:y:xs) = if x/=y then x : ll else ll
    where ll = compress (y:xs)

{-Problem 9
Pack consecutive duplicates of list elements into sublists. 
If a list contains repeated elements they should be placed in separate sublists.
Example:
(pack '(a a a a b c c a a d e e e e))
((A A A A) (B) (C C) (A A) (D) (E E E E))
Example in Haskell:
*Main> pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 
             'a', 'd', 'e', 'e', 'e', 'e']
["aaaa","b","cc","aa","d","eeee"]
-}
pack :: (Eq a) => [a] -> [[a]]
pack []  = []
pack [x] = [[x]]
pack (x:xs) = if x == head xs then (x : ll1) : (pack ll2) else [x] : pack xs
    where ll1 = takeWhile (==x) xs
          ll2 = drop (length ll1) xs

{-Problem 10
Run-length encoding of a list. 
Use the result of problem P09 to implement 
the so-called run-length encoding data compression method. 
Consecutive duplicates of elements are encoded as lists (N E) 
where N is the number of duplicates of the element E.
Example:
(encode '(a a a a b c c a a d e e e e))
((4 A) (1 B) (2 C) (2 A) (1 D)(4 E))
Example in Haskell:
encode "aaaabccaadeeee"
[(4,'a'),(1,'b'),(2,'c'),(2,'a'),(1,'d'),(4,'e')]
-}
encode :: Eq a => [a] -> [(Int,a)]
encode list = [(length $ ll!!x, head $ ll!!x) | x <- [0 .. ((length ll) - 1)]]
    where ll = pack list
